#!/bin/bash
#
# This script can be used to interact with kubernetes via ansible.

function find_base_dir {
    local real_path=$(python3 -c "import os;print(os.path.realpath('$0'))")
    local dir_name="$(dirname "$real_path")"
    if [ -z "$SNAP" ]; then
        if [[ ${dir_name} == "/usr/bin" ]]; then
            BASEDIR=/usr/share/kubez-ansible
        elif [[ ${dir_name} == "/usr/local/bin" ]]; then
            BASEDIR=/usr/local/share/kubez-ansible
        elif [[ -n ${VIRTUAL_ENV} ]] && [[ ${dir_name} == "${VIRTUAL_ENV}/bin" ]]; then
            BASEDIR="${VIRTUAL_ENV}/share/kubez-ansible"
        else
            BASEDIR="$(dirname ${dir_name})"
        fi
    else
        BASEDIR="$SNAP/share/kubez-ansible"
    fi
}

function process_cmd {
    echo "$ACTION : $CMD"
    $CMD
    if [[ $? -ne 0 ]]; then
        echo "Command failed $CMD"
        exit 1
    fi
}

function usage {
    cat <<EOF
Usage: $0 COMMAND [options]

Options:
    --inventory, -i <inventory_path>   Specify path to ansible inventory file
    --playbook, -p <playbook_path>     Specify path to ansible playbook file
    --configdir <config_path>          Specify path to directory with globals.yml
    --key -k <key_path>                Specify path to ansible vault keyfile
    --help, -h                         Show this usage information
    --tags, -t <tags>                  Only run plays and tasks tagged with these values
    --skip-tags <tags>                 Only run plays and tasks whose tags do not match these values
    --extra, -e <ansible variables>    Set additional variables as key=value or YAML/JSON passed to ansible-playbook
    --limit <host>                     Specify host to run plays
    --forks <forks>                    Number of forks to run Ansible with
    --vault-id <@prompt or path>       Specify @prompt or password file (Ansible >=  2.4)
    --ask-vault-pass                   Ask for vault password
    --vault-password-file <path>       Specify password file for vault decrypt
    --verbose, -v                      Increase verbosity of ansible-playbook

Commands:
    prechecks           Do pre-deployment checks for hosts
    bootstrap-servers   Bootstrap servers with kubernetes deploy dependencies
    post-deploy         Do post deploy on deploy node
    authorized-key      Adds SSH authorized keys for root user
    destroy             Destroy kubernetes cluter
    deploy              Deploy and start kubernetes cluster
    pull                Pull all kubernetes core images (only pulls, no running container changes)
    apply               Apply kubernetes applications
EOF
}

function bash_completion {
cat <<EOF
--inventory -i
--playbook -p
--configdir
--key -k
--help -h
--skip-tags
--tags -t
--extra -e
--passwords
--limit
--forks
--vault-id
--ask-vault-pass
--vault-password-file
--verbose -v
prechecks
bootstrap-servers
destroy
deploy
post-deploy
authorized-key
pull
apply
EOF
}

SHORT_OPTS="hi:p:t:k:e:v"
LONG_OPTS="help,inventory:,playbook:,skip-tags:,tags:,key:,extra:,verbose,configdir:,passwords:,limit:,forks:,vault-id:,ask-vault-pass,vault-password-file:,yes-i-really-really-mean-it,include-images,include-dev"

RAW_ARGS="$*"
ARGS=$(getopt -o "${SHORT_OPTS}" -l "${LONG_OPTS}" --name "$0" -- "$@") || { usage >&2; exit 2; }

eval set -- "$ARGS"

find_base_dir

INVENTORY="${BASEDIR}/ansible/inventory/all-in-one"
PLAYBOOK="${BASEDIR}/ansible/site.yml"
VERBOSITY=
EXTRA_OPTS=${EXTRA_OPTS}
CONFIG_DIR="/etc/kubez"
DANGER_CONFIRM=
INCLUDE_IMAGES=
INCLUDE_DEV=
# Serial is not recommended and disabled by default. Users can enable it by
# configuring ANSIBLE_SERIAL variable.
ANSIBLE_SERIAL=${ANSIBLE_SERIAL:-0}

while [ "$#" -gt 0 ]; do
    case "$1" in

    (--inventory|-i)
            INVENTORY="$2"
            shift 2
            ;;

    (--playbook|-p)
            PLAYBOOK="$2"
            shift 2
            ;;

    (--skip-tags)
            EXTRA_OPTS="$EXTRA_OPTS --skip-tags $2"
            shift 2
            ;;

    (--tags|-t)
            EXTRA_OPTS="$EXTRA_OPTS --tags $2"
            shift 2
            ;;

    (--verbose|-v)
            VERBOSITY="$VERBOSITY --verbose"
            shift 1
            ;;

    (--configdir)
            CONFIG_DIR="$2"
            shift 2
            ;;

    (--yes-i-really-really-mean-it)
            if [[ ${RAW_ARGS} =~ "$1" ]]
            then
                DANGER_CONFIRM="$1"
            fi
            shift 1
            ;;

    (--include-images)
            INCLUDE_IMAGES="$1"
            shift 1
            ;;

    (--include-dev)
            INCLUDE_DEV="$1"
            shift 1
            ;;

    (--key|-k)
            VAULT_PASS_FILE="$2"
            EXTRA_OPTS="$EXTRA_OPTS --vault-password-file=$VAULT_PASS_FILE"
            shift 2
            ;;

    (--extra|-e)
            EXTRA_OPTS="$EXTRA_OPTS -e $2"
            shift 2
            ;;

    (--limit)
            EXTRA_OPTS="$EXTRA_OPTS --limit $2"
            shift 2
            ;;

    (--forks)
            EXTRA_OPTS="$EXTRA_OPTS --forks $2"
            shift 2
            ;;

    (--vault-id)
            EXTRA_OPTS="$EXTRA_OPTS --vault-id $2"
            shift 2
            ;;

    (--ask-vault-pass)
            VERBOSITY="$EXTRA_OPTS --ask-vault-pass"
            shift 1
            ;;

    (--vault-password-file)
            EXTRA_OPTS="$EXTRA_OPTS --vault-password-file $2"
            shift 2
            ;;

    (--help|-h)
            usage
            shift
            exit 0
            ;;

    (--)
            shift
            break
            ;;

    (*)
            echo "error"
            exit 3
            ;;
esac
done

case "$1" in

(prechecks)
        ACTION="Pre-deployment checking"
        EXTRA_OPTS="$EXTRA_OPTS -e kube_action=precheck"
        ;;
(destroy)
        ACTION="Destroy kubernetes cluter"
        EXTRA_OPTS="$EXTRA_OPTS -e kube_action=destroy"
        if [[ "${DANGER_CONFIRM}" != "--yes-i-really-really-mean-it" ]]; then
            cat << EOF
WARNING:
    This will PERMANENTLY DESTROY all packages and host configuration.
    There is no way to recover from this action. To confirm, please add the following option:
    --yes-i-really-really-mean-it
EOF
            exit 1
        fi
        ;;
(bootstrap-servers)
        ACTION="Bootstraping servers"
        PLAYBOOK="${BASEDIR}/ansible/kubernetes-hosts.yml"
        EXTRA_OPTS="$EXTRA_OPTS -e kube_action=bootstrap-servers"
        ;;
(deploy)
        ACTION="Deploying Playbooks"
        EXTRA_OPTS="$EXTRA_OPTS -e kube_action=deploy"
        ;;
(post-deploy)
        ACTION="Post-Deploying Playbooks"
        PLAYBOOK="${BASEDIR}/ansible/post-deploy.yml"
        ;;
(authorized-key)
        ACTION="Authorized-key Playbooks"
        PLAYBOOK="${BASEDIR}/ansible/authorized-key.yml"
        EXTRA_OPTS="$EXTRA_OPTS --ask-pass"
        ;;
(pull)
        ACTION="Pulling kubernetes core images"
        EXTRA_OPTS="$EXTRA_OPTS -e kube_action=pull"
        ;;
(apply)
        ACTION="Apply kubernetes applications"
        EXTRA_OPTS="$EXTRA_OPTS -e kube_action=apply"
        ;;
(bash-completion)
        bash_completion
        exit 0
        ;;
(*)     usage
        exit 0
        ;;
esac

export ANSIBLE_HOST_KEY_CHECKING=False
export ANSIBLE_LOG_PATH=/var/log/ansible.log

CONFIG_OPTS="-e @${CONFIG_DIR}/globals.yml -e CONFIG_DIR=${CONFIG_DIR}"
CMD="ansible-playbook -i $INVENTORY $CONFIG_OPTS $EXTRA_OPTS $PLAYBOOK $VERBOSITY"
process_cmd
